package controller;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;

import chatClient.ClientMain;
import chatClient.Emission;
import chatClient.Reception;
import model.*;
import view.*;
import mappingBD.*;

public class ClientControler implements Runnable {

	private LoginModel loginModel;
	private LoginView loginView;
	private NouveauCompteView nouveauCompteView;
	private NouveauCompteModel nouveauCompteModel;
	private ChatModel chatModel;
	private ChatView chatView;
	private NouvelleSalleDialog nouvelleSalleDialog;
	private LikeMessageView likeMessageDialog;
	private ModifierProfilView modifierProfilView;
	private Emission emission;
	private Reception threadReception;
	private String sdToJoin;
	private Reception reception = null;
	private Thread t0;
	
	public void run(){
		while(true){
			if(nouveauCompteModel.getPseudo()!=null){
				try {
					t0.sleep(15000);
					synchronisation();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}		
			}			
		}
	}

	public ClientControler() {
		emission = null;
		sdToJoin = null;
	}

	public void setupViewsAndModels() {
		loginView = new LoginView(this);
		nouveauCompteModel = new NouveauCompteModel();
		// nouveauCompteView = new NouveauCompteView(this, nouveauCompteModel);
		chatModel = new ChatModel();
		// chatView = new ChatView(chatModel, this);
		modifierProfilView = new ModifierProfilView(this, nouveauCompteModel);
		loginView.showView();
	}
	
	/*
	 * Demander une synchronisation tout les 5 secondes au serveur
	 */
	public void synchronisation(){
		Synchronisation sync = new Synchronisation(new Client(nouveauCompteModel.getPseudo()));
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setSync(sync);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());
		this.chatView.updateMessages();
//		this.chatView.closeView();
//		this.chatView = new ChatView(chatModel, this);
//		this.loginView.closeView();
//		this.chatView.showView();
	}

	/*
	 * Envoyer requete type CONN
	 */
	public void retrievePseudoPassword(String pseudo, String password) {

		Client client = new Client("CONN", pseudo, password);
		modifierProfilView = new ModifierProfilView(this, nouveauCompteModel);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setClient(client);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());

		this.chatView = new ChatView(chatModel, this);
		this.loginView.closeView();
		this.chatView.showView();
		
		//Dois partir ce thread seulement apres la connexion
		t0 = new Thread(this);
		t0.start();
	}

	public void showNouveauCompteView() {
		this.nouveauCompteView = new NouveauCompteView(this, nouveauCompteModel);
		this.loginView.closeView();
		this.nouveauCompteView.showView();
	}

	public void showLoginView() {
		this.nouveauCompteView.closeView();
		this.loginView.showView();
	}

	public void showMainView() {
		this.modifierProfilView.closeView();
		this.chatView.showView();
	}

	/*
	 * Envoyer requete type PRCR -- ne pas oublier avatar...
	 */
	public void retrieveNewUserInfo(String prenom, String nom, String pseudo,
			String password, String passwordConf) {
		if (password.equals(passwordConf)) {
			Client client = new Client("PRCR", nom, prenom, pseudo, password);
			try {
				emission = new Emission();
				reception = new Reception(ClientMain.getSocket());
			} catch (IOException e) {
				e.printStackTrace();
			}
			emission.setClient(client);
			Thread t1 = new Thread(reception);
			Thread t2 = new Thread(emission);
			t1.start();
			t2.start();
			try {
				t1.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			updateModels(reception.getSync());

			this.chatView = new ChatView(chatModel, this);
			nouveauCompteView.closeView();
			chatView.showView();
		} else {
			System.out.println("ERREUR!!! " + password + " != " + passwordConf);
		}
	}

	public void saveAvatar(File file) {
		String[] parts = null;
		String ext = null;
		String fileName = file.getName();
		try {
			parts = fileName.split("\\.");
			ext = parts[1];

			ClassLoader classLoader = Thread.currentThread()
					.getContextClassLoader();
			URL url = classLoader.getResource("images/userAvatar." + ext);
			Path source = Paths.get(file.getAbsolutePath());
			Path destinationBin = Paths.get(url.toString());
			Path destinationSrc = Paths.get("src/images/userAvatar." + ext);
			try {
				Files.delete(destinationSrc);
			} catch (Exception e) {
			}
			Files.copy(source, destinationSrc);
			this.nouveauCompteModel.setPathToAvatar("images/userAvatar." + ext);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void updateAvatar() {
		BufferedImage newAvatar = null;

		ClassLoader classLoader = Thread.currentThread()
				.getContextClassLoader();
		URL url = classLoader.getResource(nouveauCompteModel.getPathToAvatar());
		// URL url = classLoader.getResource("../");
		try {
			newAvatar = resize(ImageIO.read(new File(url.toURI())), 120, 120);
		} catch (IOException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		}
		nouveauCompteView.getjLabelAvatarImage().setIcon(
				new javax.swing.ImageIcon(newAvatar));
		modifierProfilView.getjLabelAvatarImage().setIcon(
				new javax.swing.ImageIcon(newAvatar));
	}

	public void afficherAjouterSalleDiscussion() {
		nouvelleSalleDialog = new NouvelleSalleDialog(chatView.getFrame(),
				true, this);
		nouvelleSalleDialog.show();
	}

	/*
	 * Envoyer requete type SDCR
	 */
	public void retrieveNewSDInfo(String newSDName, String newSDDescription) {
		Client client = new Client(nouveauCompteModel.getPseudo());
		SalleDeDiscussion sd = new SalleDeDiscussion("SDCR", newSDName,
				newSDDescription, client);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setSd(sd);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());

		nouvelleSalleDialog.close();
		this.chatView.closeView();
		this.chatView = new ChatView(chatModel, this);
		this.chatView.showView();
	}

	/*
	 * TODO: closer le thread, pas juste le UI
	 */
	public void quitterApp() {
		chatView.closeView();
		System.out.println("Quitter la connexion");
		try {
			ClientMain.getSocket().close();
			t0.stop();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * Envoyer requete type SDCN
	 */
	//jfred 2
	public void selectionSalleDiscussion(int index) {
		sdToJoin = chatModel.getListeSalleDiscussions().get(index);
		String salleSelectionnee = chatModel.getListeSalleDiscussions().get(
				index);
		System.out.println("SD-Changement: " + salleSelectionnee);
		Client client = new Client(nouveauCompteModel.getPseudo());
		SalleDeDiscussion sd = new SalleDeDiscussion(salleSelectionnee, client);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setSd(sd);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());

		nouvelleSalleDialog.close();
		chatView.closeView();
		chatView = new ChatView(chatModel, this);
		chatView.showView();
	}

	public void modifierProfil() {
		chatView.closeView();
		modifierProfilView = new ModifierProfilView(this, nouveauCompteModel);
		modifierProfilView.showView();
	}

	/*
	 * Envoyer requete type PRMD
	 */
	public void retrieveModifiedUserInfo(String prenom, String nom,
			String pseudo, String password, String passwordConf) {
		System.out.println("Nouvelles infos entrees pour le profil du client");
		Client client = new Client("PRMD", nom, prenom, pseudo, password);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setClient(client);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());
		chatView = new ChatView(chatModel, this);
		modifierProfilView.closeView();
		chatView.showView();
		
	}

	public void annulerConnexion() {
		this.loginView.closeView();
		try {
			ClientMain.getSocket().close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		// this.threadReception.setStopFlag(true);
	}

	private BufferedImage resize(BufferedImage image, int width, int height) {
		BufferedImage bi = new BufferedImage(width, height,
				BufferedImage.TRANSLUCENT);
		Graphics2D g2d = (Graphics2D) bi.createGraphics();
		g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY));
		g2d.drawImage(image, 0, 0, width, height, null);
		g2d.dispose();
		return bi;
	}

	public void updateModels(Synchronisation sync) {
		nouveauCompteModel.setDateDerniereSynchro(sync.getDateDerniereSync());
		nouveauCompteModel.setNom(sync.getClientFaitRequete().getNom());
		nouveauCompteModel.setPrenom(sync.getClientFaitRequete().getPrenom());
		nouveauCompteModel.setPseudo(sync.getClientFaitRequete().getPseudo());
		nouveauCompteModel.setPassword(sync.getClientFaitRequete()
				.getMotDePasse());

		chatModel.setListeClients(sync.getClientConnecter());
		ArrayList<String> listeSD = new ArrayList<String>();
		for (SalleDeDiscussion sd : sync.getSalleDeDiscussions()) {
			listeSD.add(sd.getNomSalle());
			// QUE TEMPORAIRE ETANT DONNE LE COMMENT SUIVANT
			chatModel.setSalle(sd);
			// LE IF ICI NE FUNCTION PAS PCQ LA SELECTION DE LA SALLE NE
			// FONCTIONNE PAS
			if (sd.getNomSalle().equals(sdToJoin)) {
				chatModel.setSalle(sd);
			}
		}
		chatModel.setListeSalleDiscussions(listeSD);
	}

	/*
	 * Envoyer requete type MESS
	 */
	public void soumettreMessage(String message) {
		System.out.println(message);
		Client client = new Client(nouveauCompteModel.getPseudo());
		SalleDeDiscussion sd = new SalleDeDiscussion(chatModel.getSalle()
				.getNomSalle(), client);
		Message msg = new Message("MESS", message, client, sd);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setMessage(msg);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		updateModels(reception.getSync());

		chatView.closeView();
		chatView = new ChatView(chatModel, this);
		chatView.showView();
	}

	/*
	 * Envoyer requete type SDDA
	 */
	public void desabonnerSD(SalleDeDiscussion sd) {
		System.out.println("Le client ce deconnecte " + sd.getNomSalle());
		Client client = new Client(nouveauCompteModel.getPseudo());
		SalleDeDiscussion salle = new SalleDeDiscussion("SDDA",
				sd.getNomSalle(), client);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setSd(salle);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());

		chatView.closeView();
		chatView = new ChatView(chatModel, this);
		chatView.showView();
	}

	/*
	 * Envoyer requete type SDQT
	 */
	public void quitterSD(SalleDeDiscussion sd) {
		System.out.println("Le client quitte la salle " + sd.getNomSalle());
		Client client = new Client(nouveauCompteModel.getPseudo());
		SalleDeDiscussion salle = new SalleDeDiscussion("SDQT",
				sd.getNomSalle(), client);
		try {
			emission = new Emission();
			reception = new Reception(ClientMain.getSocket());
		} catch (IOException e) {
			e.printStackTrace();
		}
		emission.setSd(salle);
		Thread t1 = new Thread(reception);
		Thread t2 = new Thread(emission);
		t1.start();
		t2.start();
		try {
			t1.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		updateModels(reception.getSync());
		chatView.closeView();
		chatView = new ChatView(chatModel, this);
		chatView.showView();
	}
	
	public void apprecierUnMessage() {
		likeMessageDialog = new LikeMessageView(chatView.getFrame(), true, this);
		likeMessageDialog.show();
	}
	
	/*
	 * Envoyer requete type LIKE
	 */
	public void likeMessage(String idMessage, String selected) {
		System.out.println("Le message " + idMessage + " a l'appreciation " + selected);
//		Message mgs = new Message();
//		try {
//			emission = new Emission();
//			reception = new Reception(ClientMain.getSocket());
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//		emission.setSd(msg);
//		Thread t1 = new Thread(reception);
//		Thread t2 = new Thread(emission);
//		t1.start();
//		t2.start();
//		try {
//			t1.join();
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
//		updateModels(reception.getSync());
		
		likeMessageDialog.close();
		this.chatView.closeView();
		this.chatView = new ChatView(chatModel, this);
		this.chatView.showView();
	}

	// GETTERS AND SETTERS

	public LoginModel getLoginModel() {
		return loginModel;
	}

	public void setLoginModel(LoginModel loginModel) {
		this.loginModel = loginModel;
	}

	public LoginView getLoginView() {
		return loginView;
	}

	public void setLoginView(LoginView loginView) {
		this.loginView = loginView;
	}

	public NouveauCompteView getNouveauCompteView() {
		return nouveauCompteView;
	}

	public void setNouveauCompteView(NouveauCompteView nouveauCompteView) {
		this.nouveauCompteView = nouveauCompteView;
	}

	public NouveauCompteModel getNouveauCompteModel() {
		return nouveauCompteModel;
	}

	public void setNouveauCompteModel(NouveauCompteModel nouveauCompteModel) {
		this.nouveauCompteModel = nouveauCompteModel;
	}

	public ChatModel getChatModel() {
		return chatModel;
	}

	public void setChatModel(ChatModel chatModel) {
		this.chatModel = chatModel;
	}

	public ChatView getChatView() {
		return chatView;
	}

	public void setChatView(ChatView chatView) {
		this.chatView = chatView;
	}

	public ModifierProfilView getModifierProfilView() {
		return modifierProfilView;
	}

	public void setModifierProfilView(ModifierProfilView modifierProfilView) {
		this.modifierProfilView = modifierProfilView;
	}

	public Reception getThreadReception() {
		return threadReception;
	}

	public void setThreadReception(Reception threadReception) {
		this.threadReception = threadReception;
	}

	public String getSdToJoin() {
		return sdToJoin;
	}

	public void setSdToJoin(String sdToJoin) {
		this.sdToJoin = sdToJoin;
	}

}
